home *** CD-ROM | disk | FTP | other *** search
/ Network CD 2 / Network CD - Volume 2.iso / programs / internet / dnet / dshterm1_0.lha / client / p_term / pterm.c next >
Encoding:
C/C++ Source or Header  |  1992-02-04  |  15.0 KB  |  528 lines

  1. /**********************************************************
  2.  *                                                        *
  3.  * Minimal Term for DNET (uc) Stone, SST                  *
  4.  * Further modifications by Unknown, SST                  *
  5.  * pterm name startupfile                                 *
  6.  * the startup file is used as tho input had come from    *
  7.  * stdin (ie keyboard or pipe or what ever)               *
  8.  *                                                        *
  9.  * Set ya TABS to 4!                                      *
  10.  * Email me!! c9107253@mystra.newcastle.edu.au            *
  11.  * For any reason!! (eg DNet, AmiNet, Demos, amigas...)   *
  12.  * Please send any changes U make!                        *
  13.  *                                                        *
  14.  * Breaks out of search for port with ctrl-D              *
  15.  * all others kill program                                *
  16.  *                                                        *
  17.  * Mega-thanx to Azza of the SST for hours of DNET source *
  18.  * modification.... yes it compiles under SAS 6!          *
  19.  **********************************************************/
  20.  
  21. /* Multi input system: this one has input from shell */
  22.  
  23.  
  24. #include <exec/types.h>
  25. #include <exec/memory.h>
  26. #include <exec/ports.h>
  27. #include <dos/dos.h>
  28. #include <proto/exec.h>
  29. #include <proto/dos.h>
  30. #include <string.h>
  31.  
  32. #include <st/textmessage.h>
  33. #include <st/st_proto.h>
  34.  
  35. #define DEFHELPCHAR '?'
  36. #define EOLN        13,10
  37. #define    ctrlSEQ        '^'
  38. #define    ctrlLEN     1
  39.  
  40. #define cmdSEQ        '\\'
  41. #define cmdLEN        1
  42.  
  43.  
  44. #define NOPORTDELAY    60    /* delay when checking for non-existant port */
  45.  
  46. /* THese are the CTRL-Signals ONLY! */
  47. #define SIGNALS (SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F)
  48.  
  49. char     things0[]    = { 10, 13, 0 },
  50.         things1[]    = { 10, 0 },
  51.         things2[]    = { 13, 0 },
  52.         things3[]    = { 8, 0 },
  53.         things4[]    = { 13, 10, 0 },
  54.         *ctrlWHITE    = "^\n\r ",
  55.         *WHITE        = " \t\n\r",
  56.         *eolntok    = "\n\r";
  57.  
  58. /* Every second one is the command command. Send \ followed by command*/
  59.  
  60. char *cmds[] = {
  61.  "LFCR",    things0,    "LF & CR at transmit end of line",
  62.  "CRLF",    things4,    "CR & LF at end of line",
  63.  "LF",        things1,    "LF end of line",
  64.  "CR",        things2,    "CR end of line",
  65.  "BS",        things3,    "back space character",
  66.  "PROMPTOFF", NULL,        "main prompt off",
  67.  "PROMPT",    NULL,        "main prompt on",
  68.  "PORT",    NULL,        "new destination port (eg \p mystra1)",
  69.  "P",        NULL,        "new destination port (eg \p mystra1)",
  70.  "AUTOKILLOFF",NULL,       "don't kill server with exit",
  71.  "AUTOKILL"   ,NULL,       "kill server with exit (\q kills us & server)",
  72.  "AUTOEXITOFF",NULL,     "don't exit when destination port not found",
  73.  "AUTOEXIT"   ,NULL,    "auto exit when destination port not found",
  74.  "WAITFORPORTOFF", NULL,"ignore input if no dest port",
  75.  "WAITFORPORT",NULL,    "wait for dest port to appear when sending",
  76.  "EXECUTE", NULL,       "send a command to the AmigaShell",
  77.  "X", NULL,                "send a command to the AmigaShell",
  78.  "QUOTE",    NULL,         "send string as command to server",
  79.  "I",        NULL,        "Ask server for help/info",
  80.  "H",        NULL,        "Ask server for help/info",
  81.  "Q",        NULL,         "Quit/exit this p-term",
  82.  "E",        NULL,          "Quit/exit this p-term"
  83. };
  84.  
  85. /* if there are common parts of words (eg promptoff & prompt) makesure
  86.    the larger (promptoff) comes before */
  87.  
  88. #define CMDDIST 3                            /* strings/command */
  89.  
  90. #define CMD_LFCR            0
  91. #define CMD_CRLF            1
  92. #define CMD_LF                2
  93. #define CMD_CR                3
  94. #define CMD_BS                4
  95. #define CMD_PROMPTOFF        5
  96. #define CMD_PROMPT            6
  97. #define CMD_PORT            7
  98. #define CMD_P                8
  99. #define CMD_AUTOKILLOFF        9
  100. #define CMD_AUTOKILL        10
  101. #define CMD_AUTOEXITOFF        11
  102. #define CMD_AUTOEXIT        12
  103. #define CMD_WAITFORPORTOFF    13
  104. #define CMD_WAITFORPORT        14
  105. #define CMD_EXECUTE            15
  106. #define CMD_X                16
  107. #define CMD_QUOTE            17
  108. #define CMD_I                18
  109. #define CMD_H                19
  110. #define CMD_Q                20
  111. #define CMD_E                21
  112. #define CMDCNT                22
  113.  
  114. /* port-terminal attributes & characteristics */
  115. /* these may be modified at anytime */
  116. #define MAXPNAMESIZE 99
  117.  
  118.  
  119. /* Return codes of functions */
  120. #define RET_QUIT    0
  121. #define RET_OK        0x0001
  122. #define RET_CTRLC    0x0f00
  123. #define RET_CTRLD    0x0f10
  124. #define RET_CTRLE    0x0f20
  125. #define RET_CTRLF    0x0f30
  126. #define RET_HALTC    0x0e00
  127. #define RET_HALTD    0x0e10
  128. #define RET_HALTE    0x0e20
  129. #define RET_HALTF    0x0e30
  130. #define RET_NOPORT    0x0002
  131. #define RET_NOTHING 0x0003
  132.  
  133. char             eoln[10] = { EOLN,0 },
  134.                 ctrlseq[10] = { ctrlSEQ,0 }, ctrllen = ctrlLEN,
  135.                 cmdseq[10] = { cmdSEQ,0 }, cmdlen = cmdLEN,
  136.                 helpchar = DEFHELPCHAR,
  137.  
  138.                 *prompt = "%s > ",
  139.                 mainprompt = 0,
  140.                 autoexit = 0,
  141.                 waitport = 0,
  142.                 autokillserver = 0,
  143.                 destportname[MAXPNAMESIZE + 2],
  144.  
  145.                 stringbuf[400],
  146.                 *progname;
  147.  
  148. /* Standard Output() */
  149. long            output;
  150.  
  151. /*********************************************************/
  152. long Readln(BPTR file, char *buffer, long max)
  153. /*********************************************************
  154.            Attempt to read a line of stuff.
  155.             return 0 on the end of a file
  156. Uses the nasty method of reading one character at a time
  157. (sorry) throws away line on eof
  158. **********************************************************/
  159. {
  160. long i = 0;
  161.     do {
  162.         if(!Read(file, &buffer[i], 1))
  163.                 return(0);
  164.     } while(!charinstr(buffer[i++], eolntok) && (i < max-1) );
  165.     buffer[i] = '\0';
  166.     return(i);
  167. }
  168.  
  169.  
  170.  
  171. /*********************************************************/
  172. BOOL SafePutToPort(struct Message *message, char *portname)
  173. /*********************************************************
  174.             Only put to the port if it exists!
  175.            Forbid first then test for the port
  176.            Return NULL if port couldn't be found
  177. **********************************************************/
  178. {
  179. struct MsgPort *port;
  180.  
  181.     Forbid();
  182.     if (port = FindPort(portname)) PutMsg(port,message);
  183.     Permit();
  184.     return((BOOL)port); /* If zero, the port has gone away */
  185. }
  186.  
  187.  
  188. /*********************************************************/
  189. short SendTextMessage(char *portname,
  190.         struct TextMessage *txtmsg, struct MsgPort *ourport)
  191. /*********************************************************
  192.   Try to send a text message to a port of name "name"
  193.          Breaks sent to us cause us to quit
  194. **********************************************************/
  195. {
  196. ULONG    mask, pmask = 1 << ourport->mp_SigBit;
  197. struct TextMessage *currtxtmsg;
  198.  
  199.     /* just in case our replier doesn't */
  200.     AllocString0(&(txtmsg->RepString),0);
  201.  
  202.     while(! SafePutToPort((struct Message *)txtmsg,portname) ) {
  203.         fpf(output,"Destination port not found (CTRL-C to ignore)..\n");
  204.         if(autoexit) return(RET_QUIT);
  205.         if(!waitport) return(RET_NOPORT);
  206.         /* Where is that port??? Might hang around... just in case. */
  207.         Delay(NOPORTDELAY);
  208.         mask = SetSignal(0,SIGNALS);    /* Set all CTRL signals to 0 */
  209.         /* If we got a control signal... quit */
  210.              if(mask & SIGBREAKF_CTRL_C) return(RET_HALTC);
  211.         else if(mask & SIGBREAKF_CTRL_D) return(RET_HALTD);
  212.         else if(mask & SIGBREAKF_CTRL_E) return(RET_HALTE);
  213.         else if(mask & SIGBREAKF_CTRL_F) return(RET_HALTF);
  214.     }
  215.  
  216.     /* now we must wait for the reply! */
  217.     for(;;) {
  218.         mask = Wait(pmask | SIGNALS);
  219.         if(mask & pmask) {
  220.             while (currtxtmsg =
  221.                 (struct TextMessage *) GetMsg(ourport)) {
  222.  
  223.                 /* Write out contents of the reply string if need be */
  224.                 if(currtxtmsg->RepString.String) {
  225.                     Write(output, currtxtmsg->RepString.String,
  226.                                         STRLEN(&(currtxtmsg->RepString)));
  227.                     SafeFreeString0(&(currtxtmsg->RepString));
  228.                 }
  229.  
  230.                 /* Got our funky text back */
  231.                 return(RET_OK);
  232.             }
  233.         }
  234.         if((mask & SIGBREAKF_CTRL_C) ||
  235.           (mask & SIGBREAKF_CTRL_D) ||
  236.           (mask & SIGBREAKF_CTRL_E) ||
  237.           (mask & SIGBREAKF_CTRL_F) ) {
  238.                 fpf(output,"Sorry,  waiting for a reply from '%s'\n",portname);
  239.         }
  240.     }
  241. }
  242.  
  243.  
  244. /*********************************************************/
  245. short DoCmdSendTM(char *string, char *send,
  246.         struct TextMessage *msg, struct MsgPort *ourport)
  247. /*********************************************************
  248.  Pass a string with a user command on it and this will try
  249.                 to do stuff from that!
  250.       modifies terminal characteristics & the like
  251.   if command is unknown pass first 120 bytes of string
  252.                       to server
  253.   returns      1 if textmessage should be sent
  254.             OR 0 if unknown command
  255.             OR -1 if a QUIT command was received
  256. **********************************************************/
  257. {
  258. char    *argument, *command, *rest, backup[120];
  259. short    i;
  260.  
  261.     strncpy(backup,string,119);
  262.     backup[119] = '\0';
  263.     command = strtok(string,WHITE);
  264.     rest = strtok(NULL,NULL);
  265.     strupper(command);
  266.  
  267.     for(i = 0; i < CMDCNT*CMDDIST; i += CMDDIST) {
  268.         if(strncmp(command,cmds[i],strlen(cmds[i])) == 0) {
  269.             switch((i+CMDDIST-1)/CMDDIST) {
  270.                 case CMD_LFCR:
  271.                 case CMD_CRLF:
  272.                 case CMD_LF:
  273.                 case CMD_CR:
  274.                     strcpy(eoln,cmds[i+1]);
  275.                     fpf(output,"\nSending %s\n",cmds[i+2]);
  276.                     return(RET_OK);
  277.  
  278.                 case CMD_BS:
  279.                     strcpy(send,cmds[i+1]);
  280.                     msg->String.StrLen = -1;
  281.                     msg->String.FreeLen = 0;
  282.                     msg->String.String = send;
  283.                     msg->Command = TM_TEXT;
  284.                     fpf(output,"\nSending %s\n",cmds[i+2]);
  285.                     return(SendTextMessage(destportname,msg,ourport));
  286.  
  287.                 case CMD_PROMPT:
  288.                     mainprompt = -1;
  289.                     fpf(output,"\n%s\n",cmds[i+2]);
  290.                     return(RET_OK);
  291.  
  292.                 case CMD_PROMPTOFF:
  293.                     mainprompt = 0;
  294.                     fpf(output,"\n%s\n",cmds[i+2]);
  295.                     return(RET_OK);
  296.  
  297.                 case CMD_PORT:
  298.                 case CMD_P:
  299.                     argument = strtok(rest,WHITE);
  300.                     if(argument == NULL) {
  301.                         fpf(output,"\nUSE: %s %s (currently port is '%s')\n",
  302.                             cmds[i],cmds[i+2],destportname);
  303.                     } else {
  304.                         fpf(output,"\nPort is now '%s' (Old port was '%s')\n",
  305.                             argument,destportname);
  306.                         strncpy(destportname,argument,MAXPNAMESIZE);
  307.                     }
  308.                     return(RET_OK);
  309.  
  310.                 case CMD_AUTOKILL:
  311.                     autokillserver = 1;
  312.                     return(RET_OK);
  313.  
  314.                 case CMD_AUTOKILLOFF:
  315.                     autokillserver = 0;
  316.                     return(RET_OK);
  317.  
  318.                 case CMD_AUTOEXIT:
  319.                     autoexit = 1;
  320.                     return(RET_OK);
  321.  
  322.                 case CMD_AUTOEXITOFF:
  323.                     autoexit = 0;
  324.                     return(RET_OK);
  325.  
  326.                 case CMD_WAITFORPORT:
  327.                     waitport = 1;
  328.                     return(RET_OK);
  329.                 case CMD_WAITFORPORTOFF:
  330.                     waitport = 0;
  331.                     return(RET_OK);
  332.  
  333.                 case CMD_QUOTE:        /* send out a command to receiver */
  334.                     fpf(output,"Sending command '%s'\n",rest);
  335.                     strcpy(send,rest);
  336.                     msg->String.StrLen = -1;
  337.                     msg->String.FreeLen = 0;
  338.                     msg->String.String = send;
  339.                     msg->Command = TM_COMMAND;
  340.                     return(SendTextMessage(destportname,msg,ourport));
  341.  
  342.                 case CMD_X:
  343.                 case CMD_EXECUTE:    /* Send command to amiga dos! */
  344.                     fpf(output,"Executing '%s'\n",rest);
  345.                     Execute(rest, NULL, output);
  346.                     return(RET_OK);
  347.  
  348.                 case CMD_I:
  349.                 case CMD_H:
  350.                     msg->String.StrLen = 0;
  351.                     msg->String.FreeLen = 0;
  352.                     msg->String.String = NULL;
  353.                     msg->Command = TM_HELP;
  354.                     fpf(output,"\nAsking for server commands\n");
  355.                     return(SendTextMessage(destportname,msg,ourport));
  356.  
  357.                 case CMD_Q: case CMD_E:
  358.                     if(autokillserver) {
  359.  
  360.                         msg->String.StrLen = 0;
  361.                         msg->String.FreeLen = 0;
  362.                         msg->String.String = NULL;
  363.                         msg->Command = TM_EXIT;
  364.                         waitport = 0;    /* Make sure we don't stick around */
  365.                         SendTextMessage(destportname,msg,ourport);
  366.                     }
  367.                     return(RET_QUIT);
  368.  
  369.             }
  370.         }
  371.     }
  372.  
  373. /* otherwise send off the command to the server - we couldn't interpret */
  374.     msg->String.StrLen = -1;
  375.     msg->String.FreeLen = 0;
  376.     msg->String.String = backup;
  377.     msg->Command = TM_COMMAND;
  378.     return(SendTextMessage(destportname,msg,ourport));
  379.  
  380. }
  381.  
  382.  
  383. /*********************************************************/
  384. short DoInput(char *instring,
  385.         struct TextMessage *txtmsg, struct MsgPort *ourport)
  386. /*********************************************************
  387.         string buf is usually trashed after this!
  388. **********************************************************/
  389. {
  390. char    *temppos;
  391. short    i;
  392.  
  393.     /* DEFAULT VALUES FOR THE TEXT MESSAGE */
  394.     txtmsg->Extra = NULL;
  395.     for(i = 0; i < 8; txtmsg->Args[i++] = 0);
  396.  
  397.     /* CHECK FOR THE COMMAND SEQUENCE (THAT'S A '\' ON A NEW LINE) */
  398.     if( strncmp(instring,cmdseq,cmdlen) == 0) {
  399.  
  400.         while(strncmp(instring,cmdseq,cmdlen) == 0) instring += cmdlen;
  401.  
  402.         /* PRINT HELP TO THE USER */
  403.         if(*instring == helpchar) {
  404.             fpf(output,"\nCharacter sequences:\n");
  405.             for(i = 0; i< CMDCNT*CMDDIST; i += CMDDIST) {
  406.                 fpf(output,"\\%s\t:%s\n",cmds[i],cmds[i+2]);
  407.             }
  408.         }
  409.         else if(*instring)
  410.             return(DoCmdSendTM(instring, instring, txtmsg, ourport));
  411.         else return(RET_NOTHING);
  412.     }
  413.  
  414.     /* SEND CONTROL CHARACTERS? */
  415.     else if( strncmp(instring,ctrlseq,ctrllen) == 0) {
  416.         while(strncmp(instring,ctrlseq,ctrllen) == 0)
  417.                 instring += ctrllen;
  418.         strupper(instring);
  419.  
  420.         /* 'a'-> 1, 'b' -> 2, 'c' -> 3 etc */
  421.         for(temppos = instring;
  422.                 *temppos && !charinstr(*temppos,eoln); temppos++)
  423.                         *temppos -= ('A' - 1);
  424.         if(temppos != instring)
  425.                 fpf(output,"\nSending control characters!\n");
  426.         *temppos = '\0';
  427.  
  428.     } else
  429.         strcat(instring,eoln);
  430.  
  431.     if( txtmsg->String.StrLen    =    strlen(instring) ) {
  432.         txtmsg->String.String    =    instring;
  433.         txtmsg->String.FreeLen  =    0;
  434.         txtmsg->Command            =    TM_TEXT;
  435.         return(SendTextMessage(destportname, txtmsg, ourport));
  436.     }
  437.  
  438.     return(RET_NOTHING);
  439. }
  440.  
  441. /*********************************************************/
  442.         int main(int argc, char **argv)
  443. /*********************************************************/
  444. {
  445. struct    MsgPort *ourport = 0;
  446. struct    TextMessage *txtmsg = 0;
  447.  
  448. BPTR    startup, input;
  449.  
  450.     output = Output();
  451.     input = Input();
  452.  
  453.     fpf(output,"PTERM Terminal end shell version [shell->port] (uc) Stone, SST\n"
  454.                "email: c9107253@mystra.newcastle.edu.au (1993)\n");
  455.  
  456.     if( argc<2 ) {
  457.         fpf(output,"Use: %s [>file] [<file] portname [startupfile]\n"
  458.                    "(This portname has NOTHING to do with the DNET ports)\n",argv[0]);
  459.         return(5);
  460.     }
  461.  
  462.     progname = argv[0];
  463.     strncpy(destportname,argv[1],MAXPNAMESIZE + 1);
  464.         /* Make sure completely padded with \0 */
  465.  
  466.     fpf(output,"Sending lines to port '%s'\n"
  467.                 "Current control character prefix is '%s'\n"
  468.                 "'%s%lc' for help!\n\n", destportname, ctrlseq, cmdseq, helpchar);
  469.  
  470.     if( !(ourport = CreatePort(0,0)) ) {
  471.         fpf(output,"Reply port will not open!\n");
  472.         goto enditnow;
  473.     }
  474.  
  475.     if( !(txtmsg = (struct TextMessage *)
  476.             AllocMem(sizeof(struct TextMessage), MEMF_PUBLIC)) ) {
  477.         fpf(output,"Sorry.. Not enough memory for message structure\n");
  478.         goto enditnow;        
  479.     }
  480.  
  481. /* WRITE MESSAGE DEFAULTS? */
  482.     txtmsg->Msg.mn_Node.ln_Type    = NT_MESSAGE;
  483.     txtmsg->Msg.mn_Length        = sizeof(struct TextMessage);
  484.     txtmsg->Msg.mn_ReplyPort    = ourport;
  485.  
  486.  
  487. /* READ A STARTUP FILE? */
  488.     if(argc >= 3) {
  489.         if(startup = Open(argv[2],MODE_OLDFILE)) {
  490.             while(    Readln(startup, stringbuf, 300) ) {
  491.                 if(!strtok(stringbuf, eolntok))
  492.                     stringbuf[0] = '\0';
  493.                 if( DoInput(stringbuf, txtmsg, ourport) == RET_QUIT)
  494.                     goto enditnow;
  495.             }
  496.             Close(startup);
  497.         }
  498.         else
  499.             fpf(output,"Startup file '%s' not found.\n",argv[2]);
  500.     }
  501.  
  502. /* READ WHAT STDIN HAS TO GIVE US */
  503.     do {
  504.         if(mainprompt) fpf(output,prompt,destportname);
  505.         if(! Readln(input, stringbuf, 300) ) {
  506.             fpf(output,"\nEOF\n");
  507.             goto enditnow;
  508.         }
  509.         if(!strtok(stringbuf, eolntok))        /* remove eoln characters */
  510.                 stringbuf[0] = '\0';
  511.  
  512.     } while(DoInput(stringbuf, txtmsg, ourport) != RET_QUIT);
  513.  
  514. enditnow:
  515.     if(ourport) {
  516.         Forbid();
  517.         /* There should be no pending messages... if there are then
  518.             something is very wrong and the system is probably stuffed.. */
  519.         while((struct TextMessage *) GetMsg(ourport));
  520.         DeletePort(ourport);
  521.         Permit();
  522.     }
  523.  
  524.     if(txtmsg) FreeMem(txtmsg,sizeof(struct TextMessage));
  525.     return(0);
  526. }
  527.  
  528.